package com.lhz.framework.config;

import com.lhz.framework.manager.threadManager.BaseThreadManager;
import com.lhz.framework.manager.threadManager.factory.AsyncBean;
import com.lhz.framework.manager.threadManager.factory.AsyncFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

import java.util.Map;
import java.util.Queue;
import java.util.concurrent.*;


/**
 * @author lihuazhi
 */
@Configuration
@Slf4j
public class ThreadPoolConfig {

    /**
     * 线程池维护线程的最少数量
     */
    private final static int CORE_POOL_SIZE = 1;
    /**
     * 线程池维护线程的最大数量
     */
    private final static int MAX_POOL_SIZE = 100;
    /**
     * 线程池维护线程所允许的空闲时间
     */
    private final static int KEEP_ALIVE_TIME = 30;
    /**
     * 线程池所使用的缓存队列大小
     */
    private final static int WORK_QUEUE_SIZE = 5;

    /**
     * 用于储存在队列中的,防止重复提交,在真实场景中，可用redis代替 验证重复
     */
    final Map<String, Object> cacheMap = new ConcurrentHashMap<>();


    /**
     * 缓存队列,当线程池满了，则将存入到此缓存队列
     */
    final Queue<Object> msgQueue = new LinkedBlockingQueue<>();

    /**
     * 创建hashmap，用于存储线程
     */
    public final static ConcurrentHashMap<String, Thread> CONSOLE_THREAD_MAP = new ConcurrentHashMap<>();

    /**
     * 当线程池的容量满了，加入到缓存队列中
     */
    final RejectedExecutionHandler handler = (r, executor) -> {
        //加入到缓存队列
        AsyncBean asyncBean = ((BaseThreadManager) r).getAsyncBean();
        msgQueue.offer(asyncBean);
        log.info("加入调度线程池，线程：" + asyncBean.getThreadId());
    };


    /**
     * 创建线程池
     */
    final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new LinkedBlockingQueue<>(WORK_QUEUE_SIZE), this.handler);


    /**
     * 线程池的定时任务----> 称为(调度线程池)。此线程池支持 定时以及周期性执行任务的需求。
     */
    final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(CORE_POOL_SIZE);


    /**
     * 检查(调度线程池)，每.5秒执行一次，查看的缓存队列是否有 记录，则重新加入到线程池
     */
    final ScheduledFuture scheduledFuture = scheduler.scheduleAtFixedRate(() -> {
        //判断缓存队列是否存在记录
        if (!msgQueue.isEmpty()) {
            //当线程池的队列容量少于WORK_QUEUE_SIZE，则开始把缓存队列的线程 加入到 线程池
            if (threadPool.getQueue().size() < WORK_QUEUE_SIZE) {
                AsyncBean asyncBean = (AsyncBean) msgQueue.poll();
                AsyncFactory asyncFactory = new AsyncFactory(asyncBean);
                log.info("取缓存执行，线程：" + asyncBean.getThreadId());
                asyncFactory.execute(threadPool);
            }
        }
    }, 0, 500, TimeUnit.MILLISECONDS);

    /**
     * 将任务加入线程池
     */
    public void start(AsyncBean asyncBean) {
        //验证当前进入的任务否已经存在
        if (cacheMap.get(asyncBean.getThreadId()) == null) {
            cacheMap.put(asyncBean.getThreadId(), new Object());
            AsyncFactory asyncFactory = new AsyncFactory(asyncBean);
            asyncFactory.execute(threadPool);
        }
    }

    /**
     * 关闭线程池 - 通常情况下不会进行关闭
     */
    public void shutdown() {
        //true表示如果定时任务在执行，立即中止，false则等待任务结束后再停止
        System.out.println("终止调度线程池：" + scheduledFuture.cancel(false));
        log.info("关闭线程服务，调度线程池还有未处理的信息条数：" + msgQueue.size());
        //清空缓存,清空后缓存中后的后续任务不会继续执行
        msgQueue.clear();

        // 停止已经在运行的线程
        log.info("关闭线程池，正在运行的线程数：" + threadPool.getActiveCount());
        // 待任务执行完成后依次关闭
        threadPool.shutdown();
        // 强转关闭所有线程，可能会出现InterruptedException异常
        // try {
        //     threadPool.shutdownNow();
        // } catch (Exception e) {
        //     log.error("关闭执行中的线程");
        // }
    }

    /**
     * 关闭具体任务 - 通常情况下不会结束某个线程
     *
     * @param threadId 具体的业务线程Id
     */
    public void remove(String threadId) {
        Thread thread = CONSOLE_THREAD_MAP.get(threadId);
        if (thread != null) {
            CONSOLE_THREAD_MAP.remove(threadId);
            thread.interrupt();
        }
    }
}
